import fileService from "../service/file.service.js";
import userService from "../service/user.service.js";
import multer from "multer";
import path from "path";
import fse from "fs-extra";
import sharp from "sharp";
import "express-async-errors";
import configer from "../utils/configer.js";
import { nanoid } from "nanoid";
import ffmpeg from "fluent-ffmpeg";

ffmpeg.setFfmpegPath(process.env.FFMPEG_PATH);
const COVER_DIR = path.resolve("uploads", "covers");
const CHUNKS_DIR = path.resolve("uploads", "chunks");
const FILES_DIR = path.resolve("uploads", "files");
const HLS_DIR = path.resolve("uploads", "hls");

const diskStorage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, "uploads/");
  },
  filename: async (req, file, cb) => {
    try {
      const filename = Buffer.from(file.originalname, "latin1").toString(
        "utf8",
      );
      const fileRecord = await fileService.createFile({
        userId: req.user.id,
        filename,
        size: file.size,
        type: file.mimetype,
        parentId: req.body.parentId || null,
      });
      req.fileRecord = fileRecord;
      const extension = path.extname(filename);
      cb(null, fileRecord.id + extension);
    } catch (err) {
      cb(err);
    }
  },
});
const fileDiskStorage = multer({ storage: diskStorage }).single("file");

//上传文件
const uploadedFile = async (req, res) => {
  fileDiskStorage(req, res, async (err) => {
    if (err) {
      return res.status(400).json({ message: err.message });
    }

    await userService.increaseUsed(req.user.id, req.fileRecord.size);
    res.status(201).json({ message: "文件上传成功" });
  })

};
const memoryDiskStorage = multer({ storage: multer.memoryStorage() }).single("chunk");


//上传切片
const uploadChunk = async (req, res) => {
  const { hash, chunkHash, filename } = req.body;
  const size = parseInt(req.body.size);
  const chunk = req.file.buffer;

  const user = await userService.getUserById(req.user.id);
  if (Number(user.used) + size > Number(user.storage)) {
    return res.status(400).json({ message: "空间不足" });
  }

  const limit = configer.get('uploadSizeLimit');
  if (size > limit * 1024 * 1024) {
    return res.status(400).json({ message: `上传文件过大，不能超过${limit}MB` });
  }

  const ext = path.extname(filename).toLowerCase();
  // 临时存放切片的文件夹
  const chunkDir = path.resolve(CHUNKS_DIR, hash);
  if (!fse.existsSync(chunkDir)) {
    await fse.mkdirs(chunkDir);
  }

  // 如果存在，直接写入
  const chunkPath = path.resolve(chunkDir, chunkHash + ext);
  if (!fse.existsSync(chunkPath)) {
    await fse.writeFile(chunkPath, chunk);
  }

  return res.status(200).json({ messgae: '上传成功', size: chunk.length });
};

const mergeChunks = async (req, res) => {
  const { hash, filename, type } = req.body;
  const parentId = req.body.parentId || null;
  const size = parseInt(req.body.size);
  const userId = req.user.id;

  //判断用户空间是否足够
  const user = await userService.getUserById(userId);
  if (Number(user.used) + size > Number(user.storage)) {
    return res.status(400).json({ message: "空间不足" });
  }

  const limit = configer.get('uploadSizeLimit');
  if (size > limit * 1024 * 1024) {
    return res.status(400).json({ message: `上传文件过大，不能超过${limit}MB` });
  }

  const ext = path.extname(filename).toLowerCase();
  const filePath = path.resolve(FILES_DIR, hash + ext);
  const chunkDir = path.resolve(CHUNKS_DIR, hash);

  if (!fse.existsSync(filePath)) {
    //如果文件不存在，合并切片到此文件路径
    const chunks = await fse.readdir(chunkDir);
    if (!fse.existsSync(chunkDir) || chunks.length === 0) {
      res.status(410).json({ message: "合并失败，请重新上传" });
    }
    chunks.sort((a, b) => {
      const numA = parseInt(a.split("-")[1].split(".")[0]);
      const numB = parseInt(b.split("-")[1].split(".")[0]);
      return numA - numB;
    });
    const writeStream = fse.createWriteStream(filePath);

    for (const chunkPath of chunks) {
      const fullChunkPath = path.resolve(chunkDir, chunkPath);
      await new Promise((resolve) => {
        const readStream = fse.createReadStream(fullChunkPath);
        readStream.pipe(writeStream, { end: false }); // 不自动关闭写入流
        readStream.on("end", () => {
          console.log("切片合并中", chunkPath);
          fse.unlink(fullChunkPath).then(resolve);
        });
      });
    }

    writeStream.end(); // 手动关闭写入流
    // 删除切片目录
    fse.remove(chunkDir);
  }
  // 生成封面，完成上传
  let coverPath = path.resolve(COVER_DIR, hash + ".jpg");
  if (!fse.existsSync(coverPath)) {
    if (type.startsWith("image/")) {
      await generateImageThumbnail(filePath, coverPath);
    } else if (type.startsWith("video/")) {
      await generateVideoThumbnail(filePath, coverPath);
    }
  }
  //生成 HLS 视频
  if (type.startsWith("video/")) {
    const hlsDir = path.resolve(HLS_DIR, hash);
    const hlsPath = path.join(hlsDir, "index.m3u8");
    console.log('上传文件:', hlsPath)
    await fse.ensureDir(hlsDir);
    if (!fse.existsSync(hlsPath)) {
      generateVedeoHls(filePath, hlsPath, hash);
    }
  }


  let fileName = filename;
  const checkFilename = await fileService.checkFilename(userId, parentId, filename);
  if (checkFilename) {
    const suffix = nanoid(4);
    const ext = path.extname(filename);
    fileName = `${path.basename(filename, ext)}-${suffix}${ext}`;
  }

  const sort = getFileSort(type);
  await fileService.createFile({
    userId,
    parentId,
    size,
    filename: fileName,
    hash,
    type,
    sort,
  });
  await userService.increaseUsed(userId, size);
  res.status(200).json({ message: "文件上传成功" });
};

const getFileSort = (type) => {
  if (type === 'folder') {
    return 0; // 文件夹
  }

  // 视频类型
  if (type.startsWith('video/') || [
    'application/x-mpegURL',
    'application/vnd.apple.mpegurl'
  ].includes(type)) {
    return 1;
  }

  // 图片类型
  if (type.startsWith('image/') || [
    'application/postscript',
    'image/svg+xml'
  ].includes(type)) {
    return 2;
  }

  // 音频类型
  if (type.startsWith('audio/') || [
    'application/ogg',
    'application/x-midi'
  ].includes(type)) {
    return 3;
  }

  // 文档类型（扩展更多文档MIME类型）
  if (type.startsWith('text/') || [
    'application/pdf',
    'application/msword',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'application/vnd.ms-excel',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'application/vnd.ms-powerpoint',
    'application/vnd.openxmlformats-officedocument.presentationml.presentation',
    'application/rtf',
    'application/x-tex',
    'application/epub+zip'
  ].includes(type)) {
    return 4;
  }

  return 5; // 其他类型
}


const generateVedeoHls = (filePath, hlsPath) => {
  const keepAlive = setInterval(() => { }, 24 * 3600 * 1000);

  ffmpeg(filePath)
    .output(hlsPath)
    .outputOptions([
      '-hls_list_size 0',    // 保留所有片段
      '-hls_time 10',        // 每个分片约10秒
      '-f hls'               // 指定输出格式为HLS
    ])
    .on('end', () => {
      clearInterval(keepAlive);
      console.log('转码完成:', hlsPath);
    })
    .on('error', (err) => {
      clearInterval(keepAlive);
      console.error('转码出错:', err.message);
    })
    .run();
};

const verifyFile = async (req, res) => {
  const { hash, filename } = req.body;

  const ext = path.extname(filename).toLowerCase();
  const filePath = path.resolve(FILES_DIR, hash + ext);
  let chunks = [];
  let isUploaded = false;
  if (fse.existsSync(filePath)) {
    isUploaded = true;
  }

  const chunkDir = path.resolve(CHUNKS_DIR, hash);
  if (fse.existsSync(chunkDir)) {
    chunks = await fse.readdir(chunkDir);
  }

  res.status(200).json({ message: "文件验证成功", isUploaded, chunks });
};

function generateVideoThumbnail(videoPath, outputPath) {
  const folder = path.dirname(outputPath);
  const filename = path.basename(outputPath);
  return new Promise((resolve, reject) => {
    ffmpeg(videoPath)
      .screenshots({
        timestamps: ["00:00:01"], // 截图时间点（支持百分比如 '50%'）
        filename, // 输出文件名
        folder, // 输出目录
        size: "320x240", // 缩略图尺寸
      })
      .on("end", () => resolve(outputPath))
      .on("error", (err) => {
        console.error("生成缩略图失败:", err);
        reject(err);
      });
  });
}

async function generateImageThumbnail(inputPath, outputPath) {
  const width = 200;
  try {
    await sharp(inputPath).resize(width).jpeg({ quality: 80 }).toFile(outputPath);
  } catch (err) {
    console.error("生成缩略图失败:", err);
  }
}
function getMimeType(filename) {
  const ext = path.extname(filename).toLowerCase();
  const mimeTypes = {
    ".jpg": "image/jpeg",
    ".jpeg": "image/jpeg",
    ".png": "image/png",
    ".gif": "image/gif",
    ".webp": "image/webp",
  };
  return mimeTypes[ext] || "application/octet-stream";
}

const getCover = async (req, res) => {
  const hash = req.params.hash;
  const files = fse.readdirSync(COVER_DIR);
  const coverFile = files.find((file) => file.startsWith(hash));
  if (!coverFile) {
    return res.status(404).json({ message: "封面不存在" });
  }
  const filePath = path.join(COVER_DIR, coverFile);
  const mimeType = getMimeType(coverFile);
  res.setHeader("Content-Type", mimeType);
  fse.createReadStream(filePath).pipe(res);
};

const getUploadSizeLimit = async (req, res) => {
  const uploadSizeLimit = configer.get("uploadSizeLimit");
  res.json({ uploadSizeLimit });
}

export default {
  uploadedFile,
  memoryDiskStorage,
  uploadChunk,
  mergeChunks,
  verifyFile,
  getCover,
  getUploadSizeLimit
};
